Yes, there are some practices which are generally considered dangerous. However none of these are universally 'bad', since situations arise when even the worst of these is needed:
* a class 'X's assignment operator should return '*this' as an 'X&' (allows chaining of assignments)
* a class with any virtual fns ought to have a virtual destructor
* a class with any of {dtor, assignment-op, copy-ctor} generally needs all 3
* a class 'X's copy-ctor and assignment-op should have 'const' in the param:
'X::X(const X&)' and 'X& X::operator=(const X&)' respectively
* always use initialization lists for class sub-objects rather than assignment the performance difference for user-defined classes can be substantial (3x!)
* many assignment operators should start by testing if 'we' are 'them'; ex:
X& X::operator=(const X& x)
{
if (this == &x) return *this;
//...normal assignment duties...
return *this;
}
sometimes there is no need to check, but these situations generally correspond to when there's no need for an explicit user-specified assignment op (as opposed to a compiler-synthesized assignment-op).
* in classes that define both '+=', '+' and '=', 'a+=b' and 'a=a+b' should generally do the same thing; ditto for the other identities of builtin types (ex: a+=1 and ++a; p[i] and *(p+i); etc). This can be enforced by writing the binary ops using the 'op=' forms; ex:
X operator+(const X& a, const X& b)
{
X ans = a;
ans += b;
return ans;
}
This way the 'constructive' binary ops don't even need to be friends. But it is sometimes possible to more efficiently implement common ops (ex: if 'X' a 'String' and '+=' has to reallocate/copy string memory, it's better to know the eventual length from the beginning).
See Stroustrup/C++ Programming Language/Second Edition/'Rules of Thumb'/p.10